package tools.chapter25;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @author Kevin
 * @date 2020/4/14 13:48
 * 利用 CompletionService 实现 Dubbo 中的 Forking Cluster
 * Dubbo 中有一种叫做 Forking 的集群模式，这种集群模式下，支持并行地调用多个查询服务，只要有一个成功返回结果，整个服务就可以返回了
 */
public class ForkingByCompletionService {

    public int geocoder() {
        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        //创建CompletionService
        CompletionService<Integer> cs = new ExecutorCompletionService<>(executor);
        // 用于保存Future对象
        List<Future<Integer>> futures = new ArrayList<>();
        //提交异步任务，并保存future到futures
        futures.add(cs.submit(()->geocoderByS1()));
        futures.add(cs.submit(()->geocoderByS2()));
        futures.add(cs.submit(()->geocoderByS3()));
        // 获取最快返回的任务执行结果
        Integer r = 0;
        try {
            // 只要有一个成功返回，则break
            for (int i = 0; i < 3; i++) {
                r = cs.take().get();
                // 简单的通过判空来检查是否成功返回
                if (r != null) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            //取消所有任务
            for (Future<Integer> f: futures) {
                f.cancel(true);
            }
        }
        // 返回结果
        return r;
    }

    public static Integer geocoderByS1()  throws InterruptedException {
        Thread.sleep(100);
        return 1;
    }
    public static Integer geocoderByS2()  throws InterruptedException {
        Thread.sleep(100);
        return 2;
    }
    public static Integer geocoderByS3()  throws InterruptedException {
        Thread.sleep(100);
        return 3;
    }
}
